#   Copyright 2006 Jerome Lacoste (jerome@coffeebreaks.org)
#
#   Licensed under the Apache License, Version 2.0 (the "License");
#   you may not use this file except in compliance with the License.
#   You may obtain a copy of the License at
#
#       http://www.apache.org/licenses/LICENSE-2.0
#
#   Unless required by applicable law or agreed to in writing, software
#   distributed under the License is distributed on an "AS IS" BASIS,
#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
#   See the License for the specific language governing permissions and
#   limitations under the License.
require "digest/sha1"

class User < ActiveRecord::Base
  composed_of :tz, :class_name => 'TZInfo::Timezone', 
              :mapping => %w(time_zone identifier)

  has_many :clients, :class_name => "Client", :foreign_key => 'owner_id'
  has_many :assignments;
  has_many :assigned_projects, :class_name => "Project", :through => :assignments, :source => :project, :order => "short asc"
#  has_many :assigned_projects, :class_name => "Project", :through => :assignments

  attr_accessor :password, :password_confirmation
  attr_accessible :name, :password, :password_confirmation, :short

  validates_uniqueness_of :name, :short
  validates_presence_of :name, :password

  validates_format_of :name,
                      :with => %r{^.+@.+\..+$}i,
                      :message => "must be an email."


  before_destroy :dont_destroy_admin

  def before_create
    self.hashed_password = User.hash_password(self.password)
  end

  def after_create
    @password = nil
    @password_confirmation = nil
  end

  def before_save
    self.hashed_password = User.hash_password(self.password)
  end

  def after_save
    @password = nil
  end

  def dont_destroy_admin
    # FIXME this is a joke...
    raise "Can't destroy admin" if self.name == 'jerome.lacoste@gmail.com'
  end

  def self.login(name, password)
    hashed_password = hash_password(password || "")
    find(:first,
         :conditions => ["name = ? and hashed_password = ?", name, hashed_password])
  end

  def try_to_login
    User.login(self.name, self.password)
  end

  def to_s
    "User #{id}-#{short}-#{name}"
  end


  # composed_of only handles reader method generation '.new' while TimeZone requires instanciation through a factory method
  # would be nice to have a :class_method => 'get' in composed_of
  def tzget
     TZInfo::Timezone.get(self.timezone_name)
  end

  # Find the users assigned to a particular project
  # FIXME use associations. Check that other fields not accessible from controller
  def self.find_project_assignees(project_id)
    User.find(:all,
              :select => "users.name, users.short",
              :joins => "LEFT OUTER JOIN assignments a ON users.id = a.user_id",
              :conditions => "a.project_id = #{project_id}",
              :order => "short asc")
  end

  def is_not_assigned?
    return assigned_projects.length == 0
  end

  # FIXME unit test
  def assigned_to?(project_id)
    assignments.each { |a| 
      return true if a.project_id == project_id
    }
    false
  end

  protected
  def validate
    errors.add(:password_confirmation, "doesn't match") unless password == password_confirmation
  end

  private
  def self.hash_password(password)
    Digest::SHA1.hexdigest(password)
  end
end
